package com.flow.framework.module.call.rpc.interceptor;

import com.flow.framework.common.constant.FrameworkCommonConstant;
import com.flow.framework.common.error.SystemErrorCode;
import com.flow.framework.common.exception.CheckedException;
import com.flow.framework.common.util.verify.VerifyUtil;
import com.flow.framework.core.constant.FrameworkCoreConstant;
import com.flow.framework.core.holder.SecurityContextHolder;
import com.flow.framework.core.holder.SystemVersionContextHolder;
import com.flow.framework.module.call.rpc.manager.FeignManager;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.Target;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 微服务的feign调用链中，在header中保存当前用户信息传递到下一个微服务中
 * 当前传递的信息为：用户上下文信息和系统版本号
 *
 * @author luoguopiao
 * @version 0.0.1
 * @date 2022/2/19
 */
@RequiredArgsConstructor
@Slf4j
public class FeignSecurityContextInterceptor implements RequestInterceptor {

    private final FeignManager feignManager;

    @Override
    public void apply(RequestTemplate template) {
        // 设置Header前先删除之前的数据，避免底层对Header里的数据进行了包装导致拦截器获取到的Herder不正确
        template.removeHeader(FrameworkCoreConstant.USER_CONTEXT_HEADER_KEY);
        template.removeHeader(FrameworkCommonConstant.SYSTEM_VERSION_KEY);

        Target<?> target = template.feignTarget();
        if (!feignManager.isInnerRequest(target)) {
            return;
        }

        String userContext = SecurityContextHolder.getUserContextString();
        if (!VerifyUtil.isEmpty(userContext)) {
            try {
                String temp = URLEncoder.encode(userContext, StandardCharsets.UTF_8.name());
                template.header(FrameworkCoreConstant.USER_CONTEXT_HEADER_KEY, temp);
            } catch (UnsupportedEncodingException e) {
                log.error("context encode error.", e);
                throw new CheckedException(SystemErrorCode.SERIALIZE_ERROR, "context encode error.", e);
            }
        }

        Long systemVersion = SystemVersionContextHolder.getCurrentSystemVersion();
        if (!VerifyUtil.isEmpty(systemVersion)) {
            template.header(FrameworkCommonConstant.SYSTEM_VERSION_KEY, String.valueOf(systemVersion));
        }
    }
}
